
#pragma once
#include<iostream>
#include<string>
#include<queue>
#include<unistd.h>
#include<pthread.h>

namespace ns_threadpool
{
    template<class T>
    class ThreadPool
    {
    private:
        int _num;
        std::queue<T> _task_queue; //临界资源
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;

    public:

        void Lock()
        {
            pthread_mutex_lock(&_mtx);
        }
        void Unlock()
        {
            pthread_mutex_unlock(&_mtx);
        }
        void Wait()
        {
            pthread_cond_wait(&_cond,&_mtx);
        }
        void Wakeup()
        {
            pthread_cond_signal(&_cond);
        }
        bool IsEmpty()
        {
            return _task_queue.empty();
        }

    public:

        ThreadPool(int num=3)
            :_num(num)
            {
                pthread_mutex_init(&_mtx,nullptr);
                pthread_cond_init(&_cond,nullptr);
            } 
        
        //想要线程在类中执行类中的函数
        //要设置成static
        static void* Rountine(void* args)
        {
            pthread_detach(pthread_self());//分离不用等
            ThreadPool<T> *tp=(ThreadPool<T> *)args;
            while(true)
            {
                tp->Lock();
                while(tp->IsEmpty())
                {
                    tp->Wait(); //没任务等待
                }
                //处理任务
                int data = 0;
                tp->PopTask(&data);
                std::cout << "消费数据是: " << data << std::endl;

                tp->Unlock();
            }
        }

        void InitThreadPool()
        {
            pthread_t id;
            for(int i=0;i<3;i++)
            {
                pthread_create(&id,nullptr,Rountine,(void*)this);
            }
        }

        void PushTask(const T& in)
        {
            Lock();
            _task_queue.push(in);
            Unlock();

            Wakeup();
        }

        void PopTask(T* out)
        {
          
            *out=_task_queue.front();
            _task_queue.pop();        
        }
        ~ThreadPool()
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }
    };
}